package com.pcbly.web.components.utils;

import java.util.Hashtable;
import java.util.ResourceBundle;

import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.pcbly.web.Constants;

/**
 * need to write a dec to hex
 *  ADUtil class:
 *  <br>main task:</br>
 *  1.Connect LADP
 *  2.Authentication user and pwd
 *  3.Search User according to mail
 *  4.Create User for UnitTest
 *   
 * @author jay.han
 * 
 *
 */
@SuppressWarnings("unchecked")
public class ADUtils {
	
	/**
	 * ResourceBundle
	 */
	private static ResourceBundle rb = ResourceBundle.getBundle("ad");
	
	/**
	 * factory
	 */
	private static final String PRIVIDER = rb.getString("ldap.provider");
	/**
	 * URL: constant fields
	 */
	private static final String URL = rb.getString("ldap.url");
	/**
	 * mail extension
	 */
	private static final String mailExt = rb.getString("mail.ext");
	/**
	 * external mail extension
	 */
	private static final String extMailExt = rb.getString("ext.mail.ext");
	/**
	 * email extension
	 */
	private static final String emailExt = rb.getString("email.ext");
	/**
	 * userName
	 */
	private static final String USER = rb.getString("username");
	/**
	 * password
	 */
	private static final String PSW = rb.getString("password");
	/**
	 * search base
	 */
	private static final String base = rb.getString("search.base");
	/**
	 * filter instance
	 */
	private static final String filter = rb.getString("search.filter");
	/**
	 * logger instance
	 */
	private static final Log logger = LogFactory.getLog(ADUtils.class);

	private Hashtable<String,String> env = null;

	private int UF_ACCOUNTDISABLE = 2;

	private LdapContext ctx = null;

	private Control[] connCtls = null;

	public ADUtils() {
		env = new Hashtable<String,String>();
		env.put(Context.INITIAL_CONTEXT_FACTORY, PRIVIDER);
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
		env.put(Context.PROVIDER_URL, URL);
		/**
		 * if you want to modified password,you should use ssl connection for
		 * example: env.put(Context.SECURITY_PROTOCOL,"ssl");
		 */
		connCtls = new Control[] { new FastBindConnectionControl() };
		/**
		 * it is an anonymous bind.
		 */
		try {
			ctx = new InitialLdapContext(env, connCtls);

		} catch (NamingException e) {
			logger.error(e.getMessage(), e);
		}
	}

	public static void main(String args[]) {

		ADUtils test = new ADUtils();
		
		test.authenticate();
		//logger.info(String.valueOf(test.verifyLogin("jay.han", "ILOVEwaipo525")));
		 String userName =
		 "fbtrackadmin";
		 
		System.out.println( test.searchEmail(userName));

	}

	/**
	 * authenticate a user with default user and password
	 * 
	 * @return isOK
	 */
	public boolean authenticate() {
		boolean flag = false;
		try {
			ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, USER);
			ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, PSW);
			ctx.reconnect(connCtls);
			logger.info(USER + " is authenticated");
			flag = true;
		} catch (AuthenticationException e) {
			logger.error(USER + " is not authenticated");
		} catch (NamingException e) {
			logger.error(USER + " is not authenticated");
		}
		return flag;

	}

	/**
	 * authenticate with username and password
	 * 
	 * @return isOK
	 */
	public boolean authenticate(String user, String pwd) {
		boolean flag = false;
		try {
			ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, user + mailExt);
			ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, pwd);
			ctx.reconnect(connCtls);
			logger.info(user + " is authenticated");
			flag = true;
		} catch (AuthenticationException e) {
			logger.error(user + " is not authenticated");
		} catch (NamingException e) {
			logger.error(user + " is not authenticated");
		}
		return flag;

	}

	/**
	 * finish method
	 */
	public void finish() {
		try {
			ctx.close();
			logger.info("Context is closed");
		} catch (NamingException e) {
			logger.error("Context close failure " + e.getMessage(), e);
		}
	}
	public String searchEmail(String user){
		NamingEnumeration answer = null;
		String result = null;
		SearchControls searchCtls = new SearchControls();
		// Specify the search scope
		searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		// specify the LDAP search filter
		String searchFilter = "(&(objectCategory=person)(objectClass=user)(userPrincipalName="
				+ user + mailExt+"))";
		//logger.info(searchFilter);
		// Specify the Base for the search
		String searchBase = base;
		// initialize counter to total the group members
		// Specify the attributes to return
		 String returnedAtts[] = {"mail"};
		// "mail",
		// "displayName", "department", "userPrincipalName" };
		 searchCtls.setReturningAttributes(returnedAtts);
		 try {		// Loop
			answer = ctx.search(searchBase, searchFilter, searchCtls);
			if (answer == null || !answer.hasMoreElements()) {
				return result;
			}else{
				SearchResult sr = (SearchResult) answer.next();		
				Attributes attrs = sr.getAttributes();
				if (attrs != null) {
					Attribute attr = attrs.get("mail");
					if(attr !=null){
						for (NamingEnumeration e = attr.getAll(); e.hasMore();) {
							result =(String) e.next();
							result = result.replaceAll(emailExt, extMailExt);
							result = result.toLowerCase();
						}
					}
				}
			}	
		} catch (NamingException e) {
			logger.error("Problem searching directory: " + e.getMessage(),e);
		}
		return result;
	}
	
//	public boolean ADLogin(String user,String pwd){
//		boolean flag = true;
//		if (!"sysadmin".equals(user)) {
//			if (!authenticate()) {
//				flag = false;
//			} else {
//				NamingEnumeration answer = null;
//				try {
//					answer = searchUser(user);
//					if (answer == null || !answer.hasMoreElements()) {
//						flag = false;
//					} else if (!isUesrActive(answer)) {
//						flag = false;
//					} else if (!authenticate(user, pwd)) {
//						flag = false;
//					} 
//				} catch (NamingException e) {
//					logger.error("Problem searching directory: "
//							+ e.getMessage(), e);
//					flag = false;
//				}
//				
//			}
//		}
//		return flag;
//	}
	/**
	 * verify login
	 * 
	 * flag type: <br>
	 * 0 == normal</br> <br>
	 * 1 == userName and password not correct </br> <br>
	 * 2 == user is disable in AD</br> <br>
	 * 3 == user is not found in AD</br> <br>
	 * 4 == ldap connection error</br>
	 * 
	 * @param user
	 * @param pwd
	 * @return ISOK
	 */
	public int verifyLogin(String user, String pwd) {
		int flag = Constants.LOGIN_NORMAL;
		if (!authenticate()) {
			flag = Constants.LOGIN_LADP_ERROR;
		} else {
			NamingEnumeration answer = null;
			try {
				answer = searchUser(user);	
				if (answer == null || !answer.hasMoreElements()) {
					flag = Constants.LOGIN_NOT_EXISTED;
				} else if (!isUesrActive(answer)) {
					flag = Constants.LOGIN_DISABLED;
				} else if (!authenticate(user, pwd)) {
					flag = Constants.LOGIN_USR_PWD_NOT_MATCHED;
				}
			} catch (NamingException e) {
				logger.error("Problem searching directory: " + e.getMessage(),
						e);
				flag = Constants.LOGIN_LADP_ERROR;
			}

		}
		return flag;
	}

	/**
	 * search a user
	 * 
	 * @param user
	 * @return NamingEnumeration
	 * @throws NamingException
	 */
	private NamingEnumeration searchUser(String user) throws NamingException {
		NamingEnumeration answer = null;

		SearchControls searchCtls = new SearchControls();
		// Specify the search scope
		searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		// specify the LDAP search filter
		String searchFilter = "(&(objectCategory=person)(objectClass=user)(userPrincipalName="
				+ user + mailExt+"))";
		//logger.info(searchFilter);
		// Specify the Base for the search
		String searchBase = base;
		// initialize counter to total the group members
		try {
			answer = ctx.search(searchBase, searchFilter, searchCtls);

			return answer;
		} catch (NamingException e) {
			throw e;
		}

	}
	
	


	/**
	 * 
	 * check the user is active or not
	 * 
	 * @param answer
	 * @return isActive
	 */
	
	private boolean isUesrActive(NamingEnumeration answer) {
		boolean flag = false;
		try {
			// Loop
			if (answer != null && answer.hasMoreElements()) {
				SearchResult sr = (SearchResult) answer.next();
				//logger.debug(">>>" + sr.getName());
				Attributes attrs = sr.getAttributes();
				if (attrs != null) {
					Attribute attr = attrs.get("userAccountControl");
					for (NamingEnumeration e = attr.getAll(); e.hasMore();) {
						// logger.info(" "+ (Integer.parseInt((String) e.next())
						// & UF_ACCOUNTDISABLE));
						int userAccContrl = Integer.parseInt((String) e.next());		
						if (0 == (Integer.parseInt(Integer.toHexString(userAccContrl)) & UF_ACCOUNTDISABLE)) {
							flag = true;
						}
					}

				}
			}
		} catch (NamingException e) {
			logger.error("Problem searching directory: " + e.getMessage(), e);
		}
		return flag;

	}


	/**
	 * create a new user for test
	 * 
	 * @param sGroupName
	 * @param sUserName
	 * @return isOK
	 */
	public boolean createNewUser(String sGroupName, String sUserName) {
		try {
			// Create attributes to be associated with the new user
			Attributes attrs = new BasicAttributes(true);

			/**
			 * These are the mandatory attributes for a user object Note that
			 * Win2K3 will automatically create a random samAccountName if it is
			 * not present. (Win2K does not)
			 */
			attrs.put("objectClass", "user");
			/**
			 * When an object of the user, group, or computer class is created
			 * on a domain controller that is running on WWindows Server 2003 or
			 * later, the domain controller automatically sets the
			 * sAMAccountName attribute for the object to a unique string, if
			 * one is not specified.
			 */
			//attrs.put("sAMAccountName", "Yuna.Test");
			attrs.put("cn", sUserName);

			/**
			 * those fields are defined in the requirements
			 */
			attrs.put("mail", "JayTest@china.freeborders");

			// some useful constants from lmaccess.h
			int UF_ACCOUNTDISABLE = 0x0002;
			int UF_PASSWD_NOTREQD = 0x0020;
			// int UF_PASSWD_CANT_CHANGE = 0x0040;
			int UF_NORMAL_ACCOUNT = 0x0200;
			// int UF_DONT_EXPIRE_PASSWD = 0x10000;
			int UF_PASSWORD_EXPIRED = 0x800000;
			/**
			 * Note that you need to create the user object before you can set
			 * the password. Therefore as the user is created with no password,
			 * user AccountControl must be set to the following otherwise the
			 * Win2K3 password filter will return error 53 unwilling to perform.
			 */

			attrs.put("userAccountControl", Integer.toString(UF_NORMAL_ACCOUNT
					+ UF_PASSWD_NOTREQD + UF_PASSWORD_EXPIRED
					+ UF_ACCOUNTDISABLE));

			// Create the context
//			 Context result = ctx.createSubcontext(sUserName, attrs);
//			 System.out.println("Created disabled account for: " + sUserName);


			// set password is a ldap modify operation
			// and we'll update the userAccountControl
			// enabling the account and force the user to update ther password
			// the first time they login
			/**
			 * if you want to modify password,you need to use SSL
			 */
			/**
			 * Replace the "unicdodePwd" attribute with a new value Password
			 * must be both unicode and a quoted string
			 */
			// now add the user to a group.
			try {
				ModificationItem member[] = new ModificationItem[1];
				member[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,
						new BasicAttribute("member", sUserName));
				ctx.modifyAttributes(sGroupName, member);
				logger.info("Added user to group: " + sGroupName);

			} catch (NamingException e) {
				logger.error("Problem adding user to group: " + e.getMessage(),
						e);
			}
			logger.info("Successfully created User: " + sUserName);
			return true;

		} catch (Exception e) {
			logger.error("Problem creating object: " + e.getMessage(), e);
		}
		return false;
	}
	/**
	 * add by Rick Pan
	 * 
	 * @param model
	 * @param rs
	 * @param request
	 * @return boolean
	 * @throws Exception 
	 * 
	 */
//	public String updateADUserInfo(String email,String managerMail,HttpServletRequest request){
//		String updateFlag = "UpdateSuccess";
//		boolean authentication = authenticate();
//		
//		if(authentication){
//			try{
//				String key = "mail";
//				String userDn = getDistinguishedName(key, wrapEmail(email));
//				// for test
//				//String userDn = getDistinguishedName(key, "test3.test@china.freeborders");
//				if(null != userDn){
//					String managerDn = null;
//					String managerEmail = wrapEmail(managerMail);
//					if(!"".equals(managerEmail)){
//						managerDn = getDistinguishedName(key, managerEmail);
//					}
//					
////					ModificationItem[] modItems = warpModificationItem(model, request, managerDn);
////					ctx.modifyAttributes(userDn, modItems);
//				}else{
//					updateFlag = "FindDNError";
//				}
//			}catch(Exception e){
//				updateFlag = "ADException";
//				e.printStackTrace();
//				//throw e;
//			}
//			
//		}else{
//			updateFlag = "AuthenticationError";
//		}
//		
//		finish();
//		return updateFlag;
//	}
	
	/**
	 * add by Rick Pan
	 * 
	 * @param model
	 * @param rs
	 * @param request
	 * @return boolean
	 * @throws NamingException 
	 * 
	 */
//	public String updateADTelephoneNumber(BasicInfoModel model,HttpServletRequest request) throws NamingException{
//		String updateFlag = "UpdateSuccess";
//		boolean authentication = authenticate();
//		
//		if(authentication){
//			
//			try{
//				String key = "userPrincipalName";
//				
//				String userDn = getDistinguishedName(key, model.getUserName()+mailExt);
//				// for test
//				//String userDn = getDistinguishedName(key, "test3.test@china.freeborders");
//				if(null != userDn){
//					
//					String telephoneNumber = ("".equals(model.getOfficePhone())) ? " " : model.getOfficePhone();
//					Attribute attrTelephoneNum = new BasicAttribute("telephoneNumber", telephoneNumber);
//					ModificationItem itemTelephoneNum = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrTelephoneNum);
//					
//					String tempOffice = getCategoryCode(request,model.getOfficeId(),"lstOffice");
//					String physicalDeliveryOfficeName = ("".equals(tempOffice)) ? " " : tempOffice;
//					Attribute attrPhysicalDeliveryOfficeName = new BasicAttribute("physicalDeliveryOfficeName", physicalDeliveryOfficeName);
//					ModificationItem itemPhysicalDeliveryOfficeName = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrPhysicalDeliveryOfficeName);
//					
//					ModificationItem[] modItems = new ModificationItem[]{itemTelephoneNum, itemPhysicalDeliveryOfficeName};
//					ctx.modifyAttributes(userDn, modItems);
//				}else{
//					updateFlag = "FindDNError";
//				}
//			}catch(NamingException e){
//				updateFlag = "ADException";
//				e.printStackTrace();
//				//throw e;
//			}
//			
//		}else{
//			updateFlag = "AuthenticationError";
//		}
//		
//		finish();
//		return updateFlag;
//	}
	
	/**
	 * add by Rick Pan
	 * @param model
	 * @param officeName
	 * @param managerDn
	 * @return
	 */
//	public ModificationItem[] warpModificationItem(BasicInfoModel model, HttpServletRequest request,
//			String managerDn){
//		
//		String company = model.getEmployeeNo();
//		String givenName = model.getFirstName();
//		String sn = model.getLastName();
//		String displayName = givenName + " " + sn
//			+ (("".equals(model.getChineseName())) ? " " : "(" + model.getChineseName() + ")");
//		
//		String lstDepartment = "lstDepartment";
//		String lstPosition = "lstPosition";
//		String lstOffice = "lstOffice";
//		
//		String department = getCategoryCode(request,model.getDepartmentId(),lstDepartment);
//		String title = getCategoryCode(request,model.getPositionId(),lstPosition);
//		String tempOffice = getCategoryCode(request,model.getOfficeId(),lstOffice);
//		String office = ("".equals(tempOffice)) ? " " : tempOffice;
//		
//		String telephoneNumber = ("".equals(model.getOfficePhone())) ? " " : model.getOfficePhone();
//		
//		Attribute attrCompany = new BasicAttribute("company", company);
//		ModificationItem itemCompany = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrCompany);
//		
//		Attribute attrGivenName = new BasicAttribute("givenName", givenName);
//		ModificationItem itemGivenName = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrGivenName);
//		
//		Attribute attrSn = new BasicAttribute("sn", sn);
//		ModificationItem itemSn = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrSn);
//		
//		Attribute attrDisplayName = new BasicAttribute("displayName", displayName);
//		ModificationItem itemDisplayName = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrDisplayName);
//		
//		Attribute attrDepartment = new BasicAttribute("department", department);
//		ModificationItem itemDepartment = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrDepartment);
//		
//		Attribute attrTitle = new BasicAttribute("title", title);
//		ModificationItem itemTitle = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrTitle);
//		
//		Attribute attrTelephoneNum = new BasicAttribute("telephoneNumber", telephoneNumber);
//		ModificationItem itemTelephoneNum = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrTelephoneNum);
//		
//		
//		Attribute attrOffice = new BasicAttribute("physicalDeliveryOfficeName", office);
//		ModificationItem itemOffice = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrOffice);
//		
//		ModificationItem[] items = null;
//		if(null != managerDn){
//			Attribute attrManagerDn = new BasicAttribute("manager", managerDn);
//			ModificationItem itemManagerDn = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrManagerDn);
//			items = new ModificationItem[]{itemCompany,itemGivenName,itemSn,itemDisplayName,itemDepartment,
//					itemTitle,itemTelephoneNum,itemOffice,itemManagerDn};
//		}else{
//			items = new ModificationItem[]{itemCompany,itemGivenName,itemSn,itemDisplayName,itemDepartment,
//					itemTitle,itemTelephoneNum,itemOffice};
//		}
//		
//		return items;
//	}
	
	/**
	 * add by Rick Pan
	 * 
	 * getDistinguishedName is used to get dn for corresponding user via his/her email
	 * @return String
	 * @throws NamingException 
	 */
	public String getDistinguishedName(String key, String value) throws NamingException{
		String distinguishedName = null;
		String dnAttrID = "distinguishedName";
		String[] returningAttributes = new String[]{key,dnAttrID};
		
		SearchControls controls = new SearchControls();
		controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		controls.setReturningAttributes(returningAttributes);
		NamingEnumeration attrs = ctx.search(base, filter, controls);
		
		while (attrs.hasMore()) {
			SearchResult sr = (SearchResult) attrs.next();
			Attributes allAttr = sr.getAttributes();
			NamingEnumeration items = allAttr.getAll();
			
			String keyValue = null;
			String dnValue = null;
			while (items.hasMore()) {
				Attribute attr = (Attribute) items.next();
				NamingEnumeration values = attr.getAll();
				while (values.hasMore()) {
					Object tempValue = values.next();
					if(key.equalsIgnoreCase(attr.getID())){
						keyValue = tempValue.toString();
					}else if(dnAttrID.equalsIgnoreCase(attr.getID())){
						dnValue = tempValue.toString();
					}
				}
			}
			
			if(value.equalsIgnoreCase(keyValue)){
				distinguishedName = dnValue;
				break;
			}
		}
		return distinguishedName;
	}
	
	/**
	 * add by Rick Pan
	 * 
	 * get getCategoryCode from session list : lstOffice,lstDepartment,lstPosition
	 * @param request
	 * @param officeId
	 * @return
	 */
//	public String getCategoryCode(HttpServletRequest request,long categoryValueId, String sessionAttrName){
//		String categoryCode = null;
//		
//		List dictCategoryModels = (List)request.getSession().getAttribute(sessionAttrName);
//		if(null != dictCategoryModels){
//			Iterator iterator = dictCategoryModels.iterator();
//			while(iterator.hasNext()){
//				DictCategoryValueModel tempModel = (DictCategoryValueModel)iterator.next();
//				if(categoryValueId == tempModel.getCategoryValueId()){
//					categoryCode = tempModel.getCategoryCode();
//					break;
//				}
//			}
//		}
//		
//		return categoryCode;
//	}
	
	/**
	 * in FB Track the user email is in the type of : ***.**@freeborders.com
	 * but in AD, it is like : ***.**@china.freeborders
	 * so we need to wrap the user email from @freeborders.com to @china.freeborders
	 * @param userEmail
	 * @return
	 */
	public String wrapEmail(String userEmail){
		String tempEmail = "";
		int index = userEmail.indexOf("@");
		if(-1 != index){
			tempEmail = userEmail.substring(0, index) + emailExt;
		}else{
			tempEmail = userEmail + emailExt;
		}
		return tempEmail;
	}
	
	/**
	 * wrapFilter is used to wrap a more detail filter
	 * as the basic filter is like (&(objectCategory=person)(objectClass=user))
	 * @param key
	 * @param value
	 * @return
	 */
	public String wrapFilter(String basicFilter, String key, String value){
		int index = basicFilter.lastIndexOf(")");
		String newFilter = basicFilter.substring(0, index) + "(" + key + "=" + value + "))";
		return newFilter;
	}
	
	/**
	 * 
	 * @param email
	 * @return
	 */
	public boolean checkEmail(String email){
		boolean checkFlag = false;
		boolean authentication = authenticate();
		if(authentication){
			try{
				SearchControls controls = new SearchControls();
				controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
				controls.setReturningAttributes(new String[]{"mail"});
				String emailADType = wrapEmail(email);
				String mailFilter = wrapFilter(filter,"mail",emailADType);
				NamingEnumeration attrs = ctx.search(base, mailFilter, controls);
				
				if(attrs.hasMoreElements()){
					checkFlag = true;
				}
			}catch(Exception e){
				e.printStackTrace();
				//throw e;
			}
		}
		
		finish();
		return checkFlag;
	}
	
	/**
	 * 
	 * @param email
	 * @return
	 */
	public NamingEnumeration getOriginalAttrs(String email){
		NamingEnumeration attrs = null;
		boolean authentication = authenticate();
		if(authentication){
			try{
				SearchControls controls = new SearchControls();
				controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
				
				String[] returnAttrs = new String[]{"distinguishedName","company","givenName","sn","displayName",
						"department","title","telephoneNumber","physicalDeliveryOfficeName","manager"};
				controls.setReturningAttributes(returnAttrs);
				
				String emailADType = wrapEmail(email);
				String mailFilter = wrapFilter(filter,"mail",emailADType);
				
				attrs = ctx.search(base, mailFilter, controls);
				
			}catch(Exception e){
				e.printStackTrace();
				//throw e;
			}
		}
		
		//finish();
		return attrs;
	}
	
	/**
	 * 
	 * @param attrs
	 * @return
	 */
	public ModificationItem[] wrapAttrs(Attributes attrs){
		
		Attribute attrCompany = attrs.get("company");
		ModificationItem itemCompany = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrCompany);
		
		Attribute attrGivenName = attrs.get("givenName");
		ModificationItem itemGivenName = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrGivenName);
		
		Attribute attrSn = attrs.get("sn");
		ModificationItem itemSn = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrSn);
		
		Attribute attrDisplayName = attrs.get("displayName");
		ModificationItem itemDisplayName = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrDisplayName);
		
		Attribute attrDepartment = attrs.get("department");
		ModificationItem itemDepartment = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrDepartment);
		
		Attribute attrTitle = attrs.get("title");
		ModificationItem itemTitle = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrTitle);
		
		Attribute attrTelephoneNum = attrs.get("telephoneNumber");
		ModificationItem itemTelephoneNum = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrTelephoneNum);
		
		Attribute attrOffice = attrs.get("physicalDeliveryOfficeName");
		ModificationItem itemOffice = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrOffice);
		
		Attribute attrManagerDn = attrs.get("manager");
		ModificationItem itemManagerDn = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,attrManagerDn);
		
		ModificationItem[] items = new ModificationItem[]{itemCompany,itemGivenName,itemSn,itemDisplayName,itemDepartment,
				itemTitle,itemTelephoneNum,itemOffice,itemManagerDn};
		
		return items;
	}
	
	/**
	 * 
	 * @param attrs
	 */
	public boolean rollBackADInfo(NamingEnumeration attrs){
		boolean flag = false;
		boolean authentication = authenticate();
		if(null != attrs && authentication){	
			try {
				while (attrs.hasMore()){
					SearchResult sr = (SearchResult) attrs.next();
					Attributes allAttr = sr.getAttributes();
					String userDn = null;
					Attribute attrDN = allAttr.get("distinguishedName");
					NamingEnumeration values = attrDN.getAll();
					while (values.hasMore()) {
						userDn = values.next().toString();
					}
					if(null != userDn){
						ModificationItem[] items = wrapAttrs(allAttr);
						ctx.modifyAttributes(userDn, items);
						flag = true;
					}
				}
			} catch (NamingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		finish();
		return flag;
	}
	
	/**
	 * 
	 * @author jay.han inner class for fastBindConnection
	 */
	class FastBindConnectionControl implements Control {

		/**
		 * serial version
		 */
		private static final long serialVersionUID = -7351081611142576023L;
		/**
		 * @LDAP_OPT_FAST_CONCURRENT_BIND The Microsoft LDAP API will send an
		 *                                extended request with this name to
		 *                                Active Directory to request that all
		 *                                binds on this connection be processed
		 *                                as 'fast' binds.
		 */
		private static final String LDAP_OPT_FAST_CONCURRENT_BIND = "1.2.840.113556.1.4.1781";

		public byte[] getEncodedValue() {
			return new byte[0];
		}

		public String getID() {
			return LDAP_OPT_FAST_CONCURRENT_BIND;
		}

		public boolean isCritical() {
			return true;
		}
	}

}
